﻿using AutoMapper;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Template.Infrastructure.Dependency;
using Template.Infrastructure.Extensions;
using Template.Infrastructure.Mapping;

namespace Template.AutoMapper
{
    /// <summary>
    /// 自动映射Profile
    /// </summary>
    [Dependency(ServiceLifetime.Singleton, TryAdd = true)]
    public class AutoMapper :IAutoMap
    {

        private readonly IAutoMapAttributeTypeFinder _autoMapAttributeTypeFinder;

        private readonly IAutoMapFromAttributeTypeFinder _autoMapFromAttributeTypeFinder;

        private readonly IAutoMapToAttributeTypeFinder _autoMapToAttributeTypeFinder;

        private readonly IAutoMapProfileAttributeTypeFinder _autoMapProfileAttributeTypeFinder;

        public AutoMapper(IAutoMapAttributeTypeFinder autoMapAttributeTypeFinder, IAutoMapFromAttributeTypeFinder autoMapFromAttributeTypeFinder, IAutoMapToAttributeTypeFinder autoMapToAttributeTypeFinder, IAutoMapProfileAttributeTypeFinder autoMapProfileAttributeTypeFinder)
        {
            _autoMapAttributeTypeFinder = autoMapAttributeTypeFinder;
            _autoMapFromAttributeTypeFinder = autoMapFromAttributeTypeFinder;
            _autoMapToAttributeTypeFinder = autoMapToAttributeTypeFinder;
            _autoMapProfileAttributeTypeFinder = autoMapProfileAttributeTypeFinder;
        }


        public void CreateMap(Type[] types=null)
        {

            if (types==null)
            {
                types = new Type[] { };
            }
            var finderAutoMapTypes = types.Where(o => o.HasAttribute<AutoMapAttribute>());
            var autoMapTypes = _autoMapAttributeTypeFinder.FindAll(true).Union(finderAutoMapTypes).ToArray();


            var finderAutoMapFromTypes = types.Where(o => o.HasAttribute<AutoMapFromAttribute>());
            var autoMapFrormTypes = _autoMapFromAttributeTypeFinder.FindAll(true).Union(finderAutoMapFromTypes).ToArray();

            var finderAutoToTypes = types.Where(o => o.HasAttribute<AutoMapToAttribute>());
            var autoMapToTypes = _autoMapToAttributeTypeFinder.FindAll(true).Union(finderAutoToTypes).ToArray();
            //var autoMapProfileAttributeTypes = _autoMapProfileAttributeTypeFinder.FindAll(true);
            Mapper.Initialize(c =>
            {
                CreateProfile(types,c);
                CreateMapping<AutoMapAttribute>(autoMapTypes, c);
                CreateMapping<AutoMapFromAttribute>(autoMapFrormTypes, c);
                CreateMapping<AutoMapToAttribute>(autoMapToTypes, c);


            });
        
        }


        public void CreateProfile(Type[] types,IMapperConfigurationExpression mapperConfigurationExpression)
        {


            var finderAutoMapProfileAttributeTypes = types.Where(o => o.HasAttribute<AutoMapProfileAttribute>() && o != null);
            var autoMapProfileTypes= _autoMapProfileAttributeTypeFinder.FindAll(true).Union(finderAutoMapProfileAttributeTypes).Distinct();

            foreach (var autoMapProfileType in autoMapProfileTypes)
            {
                mapperConfigurationExpression.AddProfile(autoMapProfileType);
            }

        }


        private void CreateMapping<TAttribute>(Type[] sourceTypes, IMapperConfigurationExpression mapperConfigurationExpression)
        where TAttribute : AutoMapAttribute
        {
            foreach (var sourceType in sourceTypes)
            {
                var attribute = sourceType.GetCustomAttribute<TAttribute>();
                if (attribute.TargetTypes?.Count() <= 0)
                {
                    return;
                }
                foreach (var tatgetType in attribute.TargetTypes)
                {

                    if (attribute.Direciton.HasFlag(AutoMapDirection.To))
                    {
                        mapperConfigurationExpression.CreateMap(sourceType, tatgetType);
                    }

                    if (attribute.Direciton.HasFlag(AutoMapDirection.From))
                    {
                        mapperConfigurationExpression.CreateMap(tatgetType, sourceType);
                    }

                }
            }

        }
    }
}
